/**
 * Octopus, an XMMS2 client.
 * Copyright (C) 2014 Octopus Team
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

namespace OctopusUi {
	public class UiTracklistPanel : Mx.Frame, IKeyFocusActor {
		private const int PANELWIDTH = 670;
		private const int ICONSIZE = 30;

		private Octopus.Album album_model;
		private Mx.Frame tracklistPanelLayout;

		public bool use_texture_cache { get; set; default = false; }

		public signal void show_message_bar_text (string message);
		public signal void tracklist_panel_close ();

		public UiTracklistPanel (Octopus.IMedialibInfo tracklist_model) {
			this.album_model = (Octopus.Album) tracklist_model;
			var tracklistPanelBackgroundStack = new Mx.Stack ();
			tracklistPanelBackgroundStack.style_class = "tracklistPanel-background-cover";
			tracklistPanelBackgroundStack.reactive = true; //cover medialibPanel
			this.add_child (tracklistPanelBackgroundStack);

			var tracklistPanelBackgroundClose = new Mx.Button ();
			tracklistPanelBackgroundClose.style_class = "tracklistPanel-background-close";
			tracklistPanelBackgroundClose.clicked.connect (() => {
				tracklist_panel_close ();
			});
			tracklistPanelBackgroundStack.add_child (tracklistPanelBackgroundClose);

			var tracklistPanelBackgroundLayout = new Mx.BoxLayout ();
			tracklistPanelBackgroundLayout.orientation = Mx.Orientation.HORIZONTAL;
			tracklistPanelBackgroundLayout.x_align = Clutter.ActorAlign.END;
			tracklistPanelBackgroundLayout.spacing = 20;
			tracklistPanelBackgroundStack.add_child (tracklistPanelBackgroundLayout);

			var tracklistPanelStack = new Mx.Stack ();
			tracklistPanelStack.name = "tracklistPanel-background";
			tracklistPanelStack.width = PANELWIDTH;
			tracklistPanelStack.reactive = true;
			tracklistPanelBackgroundLayout.add_child (tracklistPanelStack);
			tracklistPanelStack.button_release_event.connect(() => {
				key_focus ();
				return false; //propagate
			});

			var tracklistPanelPlaylistSpaceholder = new Mx.Frame ();
			tracklistPanelPlaylistSpaceholder.width = UiPlaylistPanel.PLAYLISTWIDTH;
			tracklistPanelBackgroundLayout.add_child (tracklistPanelPlaylistSpaceholder);

			var tracklistPanelVBox = new Mx.BoxLayout ();
			tracklistPanelVBox.orientation = Mx.Orientation.VERTICAL;
			tracklistPanelVBox.x_align = Clutter.ActorAlign.FILL;
			tracklistPanelVBox.y_align = Clutter.ActorAlign.FILL;
			tracklistPanelStack.add_child (tracklistPanelVBox);

			//artist album
			var tracklistPanelArtist = new Mx.Label ();
			tracklistPanelArtist.style_class = "tracklistPanel-artist";
			tracklistPanelArtist.text = album_model.get_artist_performer ();
			tracklistPanelVBox.add_child (tracklistPanelArtist);
			var tracklistPanelAlbum = new Mx.Label ();
			tracklistPanelAlbum.style_class = "tracklistPanel-album";
			tracklistPanelAlbum.text = album_model.get_album_partofset ();
			tracklistPanelVBox.add_child (tracklistPanelAlbum);
			this.tracklistPanelLayout = new Mx.Frame ();
			this.tracklistPanelLayout.style_class = "tracklistPanel-layout-album";
			tracklistPanelVBox.add_child (this.tracklistPanelLayout);

			ulong addSignalId =
			tracklist_model.add.connect (() => {
				//we expect only 1 album added
				var album = new UiAlbumPanel (/*MedialibTracklist*/this.album_model, this.use_texture_cache);
				this.tracklistPanelLayout.add_child (album);
			});
			ulong addFinishedSignalId = 0;
			addFinishedSignalId =
			tracklist_model.add_finished.connect (() => {
				tracklist_model.disconnect (addSignalId);
				tracklist_model.disconnect (addFinishedSignalId);
			});

			var tracklistPanelCloseButton = new Mx.Button ();
			tracklistPanelCloseButton.style_class = "tracklistPanel-close";
			tracklistPanelCloseButton.x_align = Clutter.ActorAlign.END;
			tracklistPanelCloseButton.y_align = Clutter.ActorAlign.START;
			tracklistPanelCloseButton.height = ICONSIZE;
			tracklistPanelCloseButton.width = ICONSIZE;
			tracklistPanelCloseButton.clicked.connect (() => {
				tracklist_panel_close ();
			});
			tracklistPanelStack.add_child (tracklistPanelCloseButton);
			var tracklistPanelOverlay = new Mx.Frame ();
			tracklistPanelOverlay.name = "tracklistPanel-overlay";
			tracklistPanelStack.add_child (tracklistPanelOverlay);
		}

		public void tracklistPanelShow () {
			this.album_model.request_data ();
			key_focus ();
		}

		public void onKeyPressEvent (Gdk.EventKey event) {
			var scrollActor = ((UiAlbumPanel)this.tracklistPanelLayout.get_child_at_index (0)).albumPanelTracklist;
			if (event.keyval == Gdk.Key.Home) { //Home
				scrollActor.vertical_adjustment.value = 0;
			}
			if (event.keyval == Gdk.Key.End) { //End
				scrollActor.vertical_adjustment.value = scrollActor.vertical_adjustment.upper;
			}
			if (event.keyval == Gdk.Key.Page_Up) { //Page_Up
				scrollActor.vertical_adjustment.value =
				    scrollActor.vertical_adjustment.value
				  - scrollActor.vertical_adjustment.page_increment;
			}
			if (event.keyval == Gdk.Key.Page_Down) { //Page_Down
				scrollActor.vertical_adjustment.value =
				    scrollActor.vertical_adjustment.value
				  + scrollActor.vertical_adjustment.page_increment;
			}
			if (event.keyval == Gdk.Key.Up) { //Up
				if ((event.state & Gdk.ModifierType.SHIFT_MASK) == Gdk.ModifierType.SHIFT_MASK) {
					scrollActor.add_selected_prev ();
				}
				scrollActor.vertical_adjustment.value =
				    scrollActor.vertical_adjustment.value
				  - scrollActor.vertical_adjustment.step_increment;
			}
			if (event.keyval == Gdk.Key.Down) { //Down
				if ((event.state & Gdk.ModifierType.SHIFT_MASK) == Gdk.ModifierType.SHIFT_MASK) {
					scrollActor.add_selected_next ();
				}
				scrollActor.vertical_adjustment.value =
				    scrollActor.vertical_adjustment.value
				  + scrollActor.vertical_adjustment.step_increment;
			}
		}
	}

	public class UiAlbumPanel : Mx.Frame {
		private const int ICONSIZE = 30;
		private const int ICONSIZE_SMALL = 20;
		private const int TRACKLISTWIDTH = 320;

		private Octopus.Album album_model;
		public  OctopusMx.MxTracklist albumPanelTracklist;
		private Gee.ArrayList<int>    id_list;

		public UiAlbumPanel (Octopus.MedialibTracklist tracklist_model, bool use_texture_cache) {
			//requires: tracklist_model of type Album
			this.album_model = (Octopus.Album) tracklist_model;
			this.id_list = new Gee.ArrayList<int> ();
			var albumPanelAlbumartTracklistTable = new Mx.Table ();
			albumPanelAlbumartTracklistTable.x_align = Clutter.ActorAlign.FILL;
			albumPanelAlbumartTracklistTable.y_align = Clutter.ActorAlign.FILL;
			this.add_child (albumPanelAlbumartTracklistTable);

			//albumart
			var albumArtStack = new Mx.Stack ();
			albumArtStack.name = "albumPanel-albumart-background";
			albumArtStack.y_align = Clutter.ActorAlign.START;
			albumPanelAlbumartTracklistTable.insert_actor (albumArtStack, 0, 0);
			var albumArt = new UiAlbumArt (300/*albumArtSize*/, use_texture_cache);
			albumArt.loadAlbumArt (this.album_model.picture_front);
			albumArt.defaultAlbumArtArtist.text = this.album_model.artist;
			albumArt.defaultAlbumArtAlbum.text = this.album_model.album;
			albumArtStack.add_child (albumArt);
			var albumArtOverlay = new Mx.Frame ();
			albumArtOverlay.name = "albumPanel-albumart-overlay";
			albumArtOverlay.reactive = true;
			albumArtStack.add_child (albumArtOverlay);
			//change albumart button
			var changeAlbumArtButton =  new Mx.Button ();
			changeAlbumArtButton.style_class = "albumPanel-albumart-change";
			changeAlbumArtButton.width = ICONSIZE;
			changeAlbumArtButton.height = ICONSIZE;
			changeAlbumArtButton.x_align = Clutter.ActorAlign.END;
			changeAlbumArtButton.y_align = Clutter.ActorAlign.END;
			changeAlbumArtButton.visible = false;
			albumArtOverlay.add_child (changeAlbumArtButton);
			albumArtOverlay.enter_event.connect (() => {
				changeAlbumArtButton.visible = true;
				return true; //propagate
			});
			albumArtOverlay.leave_event.connect (() => {
				changeAlbumArtButton.visible = false;
				return true; //propagate
			});
			changeAlbumArtButton.clicked.connect (() => {
				var file_chooser = new Gtk.FileChooserDialog ("Select cover art image", null,
				                                              Gtk.FileChooserAction.OPEN,
				                                              Gtk.Stock.CANCEL, Gtk.ResponseType.CANCEL,
				                                              Gtk.Stock.OK, Gtk.ResponseType.OK);
				var filter = new Gtk.FileFilter ();
				filter.set_filter_name ("Images");
				filter.add_pattern ("*.png");
				filter.add_pattern ("*.jpg");
				filter.add_pattern ("*.bmp");
				file_chooser.add_filter (filter);

				file_chooser.response.connect ((response) => {
					if (response == Gtk.ResponseType.OK) {
						string filename;
						filename = file_chooser.get_filename();
						album_model.set_album_art (filename, id_list);
					}
					file_chooser.destroy ();
				});
				file_chooser.show ();
				
				
			});

			//tracklist
			var albumPanelTracklistVBox = new Mx.BoxLayout ();
			albumPanelTracklistVBox.style_class = "albumPanel-tracklist-vbox";
			albumPanelTracklistVBox.orientation = Mx.Orientation.VERTICAL;
			albumPanelAlbumartTracklistTable.insert_actor (albumPanelTracklistVBox, 0, 1);
			var albumPanelTracklistControl = new Mx.BoxLayout ();
			albumPanelTracklistControl.style_class = "albumPanel-control";
			albumPanelTracklistControl.orientation = Mx.Orientation.HORIZONTAL;
			albumPanelTracklistControl.x_align = Clutter.ActorAlign.END;
			albumPanelTracklistVBox.add_child (albumPanelTracklistControl);
			var albumPanelTracklistSelectAllButton = new Mx.Button ();
			albumPanelTracklistSelectAllButton.style_class = "albumPanel-tracklist-select-all";
			albumPanelTracklistSelectAllButton.width = ICONSIZE_SMALL;
			albumPanelTracklistSelectAllButton.height = ICONSIZE_SMALL;
			albumPanelTracklistSelectAllButton.is_toggle = true;
			albumPanelTracklistControl.add_child (albumPanelTracklistSelectAllButton);
			albumPanelTracklistSelectAllButton.clicked.connect (() => {
				if (albumPanelTracklistSelectAllButton.toggled) {
					for (int i=0; i<this.albumPanelTracklist.get_list_size (); i++) {
						this.albumPanelTracklist.set_selected (this.albumPanelTracklist.get_track (i));
					}
				} else {
					this.albumPanelTracklist.unselect_tracklist ();
				}
			});
			var albumPanelTracklistAddAllButton = new Mx.Button ();
			albumPanelTracklistAddAllButton.style_class = "albumPanel-tracklist-add-all";
			albumPanelTracklistAddAllButton.width = ICONSIZE_SMALL;
			albumPanelTracklistAddAllButton.height = ICONSIZE_SMALL;
			albumPanelTracklistControl.add_child (albumPanelTracklistAddAllButton);
			albumPanelTracklistAddAllButton.clicked.connect (() => {
				for (int i=0; i<this.albumPanelTracklist.get_list_size (); i++) {
					Octopus.Global.get ().get_active_playlist ().xmms_playlist_add (this.albumPanelTracklist.get_track (i).track_model.id);
				}
			});

			var albumPanelTracklistLayout = new Mx.ScrollView ();
			albumPanelTracklistLayout.style_class = "albumPanel-tracklist-scrollview";
			albumPanelTracklistLayout.y_align = Clutter.ActorAlign.FILL;
			albumPanelTracklistLayout.width = TRACKLISTWIDTH;
			albumPanelTracklistVBox.add_child (albumPanelTracklistLayout);
			this.albumPanelTracklist = new OctopusMx.MxTracklist ();
			this.albumPanelTracklist.enable_drag_action ();
			this.albumPanelTracklist.style_class = "albumPanel-tracklist";
			this.albumPanelTracklist.orientation = Mx.Orientation.VERTICAL;
			albumPanelTracklistLayout.add_child (this.albumPanelTracklist);

			ulong addTrackSignalId =
			tracklist_model.add_track.connect((/*MedialibTracklist*/tracklist_model, /*Track*/track_model) => {
				id_list.add (track_model.id);
				var track = new OctopusMx.MxFrameTrack (track_model, "tracklistentry-background", "tracklistentry-overlay");
				track.reactive = true;
				track.button_release_event.connect ((/*Clutter.ButtonEvent*/ event) => {
					if ((event.button == 1) && (event.click_count == 1)) {  //left mouse button
						if ((event.modifier_state & Clutter.ModifierType.CONTROL_MASK) == Clutter.ModifierType.CONTROL_MASK) {
							//toggle selected
							this.albumPanelTracklist.toggle_selected (track);
						} else if ((event.modifier_state & Clutter.ModifierType.SHIFT_MASK) == Clutter.ModifierType.SHIFT_MASK) {
							//select all actors between this and the last selected actor
							this.albumPanelTracklist.multi_select (track);
						} else {
							//select one actor, unselect all others
							this.albumPanelTracklist.unselect_tracklist ();
							this.albumPanelTracklist.set_selected (track);
						}
					}
					if ((event.button == 1) && (event.click_count == 2)) { //double click (left)
						Octopus.Global.get ().get_active_playlist ().xmms_playlist_add(track.track_model.id);
					}
					if ((event.button == 3) && (event.click_count == 1)) {  //right mouse button
					}
					return false; //propagate
				});
				var tracklistEntryContent = new TracklistEntryContent (track_model);
				track.get_track_content ().add_child (tracklistEntryContent);
				var tracklistEntryMouseOverMenu = new TracklistEntryMouseOverMenu (track, this.albumPanelTracklist);
				track.get_track_mouse_over_menu ().add_child (tracklistEntryMouseOverMenu);
				var tracklistEntryDragHandleContent = new TracklistEntryDragHandleContent (track_model);
				track.get_drag_handle ().add_child (tracklistEntryDragHandleContent);
				this.albumPanelTracklist.add_track (track);
			});
			ulong addTrackFinishedSignalId = 0;
			addTrackFinishedSignalId =
			tracklist_model.add_track_finished.connect(() => {
				tracklist_model.disconnect (addTrackSignalId);
				tracklist_model.disconnect (addTrackFinishedSignalId);
			});
			tracklist_model.requestTracklist();
		}
	}

	public class TracklistEntryContent : Mx.Frame {
		private const int TRACKNRWIDTH = 40;
		private const int TITLEWIDTH = 215;
		private const int DURATIONWIDTH = 45;

		public TracklistEntryContent (Octopus.Track track_model) {
			var tracklistEntryLayoutBoxHorizontal = new Mx.BoxLayout ();
			tracklistEntryLayoutBoxHorizontal.orientation = Mx.Orientation.HORIZONTAL;
			this.add_child (tracklistEntryLayoutBoxHorizontal);

			var tracklistEntryTracknr = new Mx.Label ();
			tracklistEntryTracknr.style_class = "tracklistentry-tracknr";
			tracklistEntryTracknr.width = TRACKNRWIDTH;
			tracklistEntryLayoutBoxHorizontal.add_child (tracklistEntryTracknr);
			tracklistEntryTracknr.text = track_model.tracknr.to_string ();

			var tracklistEntryTitleArtistVBox = new Mx.BoxLayout ();
			tracklistEntryTitleArtistVBox.orientation = Mx.Orientation.VERTICAL;
			tracklistEntryLayoutBoxHorizontal.add_child (tracklistEntryTitleArtistVBox);

			var tracklistEntryTitle = new Mx.Label ();
			tracklistEntryTitle.style_class = "tracklistentry-title";
			tracklistEntryTitle.width = TITLEWIDTH;
			tracklistEntryTitleArtistVBox.add_child (tracklistEntryTitle);
			tracklistEntryTitle.text = track_model.title;

			var tracklistEntryArtist = new Mx.Label ();
			tracklistEntryArtist.style_class = "tracklistentry-artist";
			tracklistEntryArtist.width = TITLEWIDTH;
			tracklistEntryTitleArtistVBox.add_child (tracklistEntryArtist);
			tracklistEntryArtist.text = track_model.artist;

			var tracklistEntryDuration = new Mx.Label ();
			tracklistEntryDuration.style_class = "tracklistentry-duration";
			tracklistEntryDuration.width = DURATIONWIDTH;
			tracklistEntryLayoutBoxHorizontal.add_child (tracklistEntryDuration);
			tracklistEntryDuration.text = Octopus.Utils.format_duration (track_model.duration);
		}
	}

	public class TracklistEntryMouseOverMenu : Mx.Frame {
		private const int MENUICONSIZE = 15;

		public TracklistEntryMouseOverMenu (OctopusMx.MxFrameTrack track, OctopusMx.MxTracklist tracklist) {
			//mouse-over-menu buttons
			var tracklistEntryMenuLayout = new Mx.BoxLayout ();
			tracklistEntryMenuLayout.style_class = "tracklistentry-menu-layout";
			tracklistEntryMenuLayout.orientation = Mx.Orientation.HORIZONTAL;
			tracklistEntryMenuLayout.x_align = Clutter.ActorAlign.END;
			tracklistEntryMenuLayout.y_align = Clutter.ActorAlign.END;
			this.add_child (tracklistEntryMenuLayout);
			//append
			var tracklistEntryMenuAppend = new Mx.Button ();
			tracklistEntryMenuAppend.style_class = "tracklistentry-menu-append";
			tracklistEntryMenuAppend.height = MENUICONSIZE;
			tracklistEntryMenuAppend.width = MENUICONSIZE;
			tracklistEntryMenuLayout.add_child (tracklistEntryMenuAppend);
			tracklistEntryMenuAppend.clicked.connect (() => {
				Octopus.Global.get ().get_active_playlist ().xmms_playlist_add(track.track_model.id);
			});
			//selected
			var tracklistEntryMenuSelected = new Mx.Button ();
			tracklistEntryMenuSelected.style_class = "tracklistentry-menu-selected";
			tracklistEntryMenuSelected.height = MENUICONSIZE;
			tracklistEntryMenuSelected.width = MENUICONSIZE;
			tracklistEntryMenuSelected.is_toggle = true;
			tracklistEntryMenuLayout.add_child (tracklistEntryMenuSelected);
			tracklistEntryMenuSelected.clicked.connect (() => {
				tracklist.toggle_selected (track);
			});
			track.notify["selected"].connect (() => {
				if (track.selected) {
					tracklistEntryMenuSelected.toggled = true;
				} else {
					tracklistEntryMenuSelected.toggled = false;
				}
			});
			//play
			var tracklistEntryMenuPlay = new Mx.Button ();
			tracklistEntryMenuPlay.style_class = "tracklistentry-menu-play";
			tracklistEntryMenuPlay.height = MENUICONSIZE;
			tracklistEntryMenuPlay.width = MENUICONSIZE;
			tracklistEntryMenuLayout.add_child (tracklistEntryMenuPlay);
			tracklistEntryMenuPlay.clicked.connect (() => {
				Octopus.Global.get ().get_active_playlist ().xmms_playlist_add_and_set_next(track.track_model.id);
			});
		}
	}

	public class TracklistEntryDragHandleContent : Mx.Frame {
		private const int TITLEWIDTH = 215;

		public TracklistEntryDragHandleContent (Octopus.Track track_model) {
			var dragHandleBackground = new Mx.Frame ();
			dragHandleBackground.style_class = "tracklistentrydraghandle-background";
			this.add_child (dragHandleBackground);

			var dragHandleTitleArtistVBox = new Mx.BoxLayout ();
			dragHandleTitleArtistVBox.orientation = Mx.Orientation.VERTICAL;
			dragHandleBackground.add_child (dragHandleTitleArtistVBox);

			var dragHandleTitle = new Mx.Label ();
			dragHandleTitle.style_class = "tracklistentrydraghandle-title";
			dragHandleTitle.width = TITLEWIDTH;
			dragHandleTitle.text = track_model.title;
			dragHandleTitleArtistVBox.add_child (dragHandleTitle);

			var dragHandleArtist = new Mx.Label ();
			dragHandleArtist.style_class = "tracklistentrydraghandle-artist";
			dragHandleArtist.text = track_model.artist;
			dragHandleTitleArtistVBox.add_child (dragHandleArtist);
		}
	}
}
